package main

import (
	"fmt"
	"os"
)

/*
1、介绍
链表是有序的列表，是通过指针指向下一个节点
说明：一般来说，为了比较好的对单链表进行增删改查的操作，都会给它设置一个头结点
头结点的作用主要是用来标识链表头，本身这个结点不存放数据
2、实例
使用带head头的单向链表实现水浒英雄进行管理
(1)完成对英雄人物的增删改查操作
(2)第一种方法在添加英雄时，直接添加到链表的尾部
(3)第二种方式在添加英雄时，根据排名将英雄插入到指定位置（如果有这个排名，则添加失败，并给出提示）
*/
//定义一个HeroNode
type HeroNode struct {
	no       int
	name     string
	nickname string
	next     *HeroNode //这个表示指向下一个结点
}

//给链表插入一个结点
//编写第一种插入方法，在单链表的最后加入
func InsertHeroNode(head *HeroNode, newHeroNode *HeroNode) {
	//思路
	//1先找到该链表的最后这个结点
	//2创建一个辅助结点 （帮忙）
	temp := head
	for {
		if temp.next == nil { //表示找到最后
			break
		}
		temp = temp.next //让temp不断的指向下一个结点
	}
	//3将newHeroNode加入到链表的最后
	temp.next = newHeroNode
	fmt.Println("插入成功")
}

//编写第二种插入方式，根据no的编号从小到大插入
func InsertHeroNode2(head *HeroNode, newHeroNode *HeroNode) {
	//思路
	//1找到适当的结点
	//2创建一个辅助结点
	temp := head
	flag := true
	//让插入的结点的no和temp的下一个结点的no比较
	for {
		if temp.next == nil { //说明到链表的最后了
			break
		} else if temp.next.no > newHeroNode.no {
			//说明newHeroNode就应该插入到temp后面
			break
		} else if temp.next.no == newHeroNode.no {
			//说明我们的链表中已经有这个no，就不插入
			flag = false
			break
		}
		temp = temp.next
	}
	if !flag {
		fmt.Println("已经存在no=", newHeroNode.no)
		return
	} else {
		newHeroNode.next = temp.next
		temp.next = newHeroNode
		fmt.Println("有序插入成功")
	}
}

//删除一个节点
func DelHeroNode(head *HeroNode, id int) {
	temp := head
	flag := false
	//找到要删除结点的no和temp的下一个结点的no比较
	for {
		if temp.next == nil { //说明到链表的最后了
			break
		} else if temp.next.no == id {
			//说明找到了
			flag = true
			break
		}
		temp = temp.next
	}
	if flag { //找到，删除
		temp.next = temp.next.next
		fmt.Println("删除成功")

	} else {
		fmt.Println("sorry,要删除的id不存在")
	}
}

//显示链表的所有结点信息
func ListHeroNode(head *HeroNode) {
	//1创建一个辅助结点
	temp := head
	//先判断该链表是不是一个空的链表
	if temp.next == nil {
		fmt.Println("空链表")
		return
	}
	//2遍历这个链表
	for {
		fmt.Printf("[%d,%s,%s] -> ", temp.next.no, temp.next.name, temp.next.nickname)
		//判断是否到链表最后
		temp = temp.next
		if temp.next == nil {
			break
		}
	}
	fmt.Println()
}
func main() {
	//1先创建一个头结点
	head := &HeroNode{}
	var key string
	var no int
	var name string
	var nickname string
	for {
		fmt.Println("1输入add1表示使用插入方法1添加数据到链表")
		fmt.Println("2输入add2表示使用插入方法2添加数据到链表")
		fmt.Println("3输入del表示从链表删除数据")
		fmt.Println("4输入show表示显示链表")
		fmt.Println("5输入exit表示退出链表")
		fmt.Scanln(&key)
		switch key {
		case "add1":
			fmt.Println("输入序号：")
			fmt.Scanln(&no)
			fmt.Println("输入姓名：")
			fmt.Scanln(&name)
			fmt.Println("输入昵称：")
			fmt.Scanln(&nickname)
			//2创建一个新的HeroNode
			hero := &HeroNode{
				no:       no,
				name:     name,
				nickname: nickname,
			}
			//3加入
			InsertHeroNode(head, hero)
		case "add2":
			fmt.Println("输入序号：")
			fmt.Scanln(&no)
			fmt.Println("输入姓名：")
			fmt.Scanln(&name)
			fmt.Println("输入昵称：")
			fmt.Scanln(&nickname)
			//2创建一个新的HeroNode
			hero := &HeroNode{
				no:       no,
				name:     name,
				nickname: nickname,
			}
			//3加入
			InsertHeroNode2(head, hero)
		case "del":
			fmt.Println("输入要删除的id：")
			fmt.Scanln(&no)
			//4删除
			DelHeroNode(head, no)
		case "show":
			fmt.Println("链表情况如下：")
			//5显示
			ListHeroNode(head)
		case "exit":
			os.Exit(0)
		}

	}
}
